/********************************************************************************
 * Copyright (c) 2019 [Open Lowcode SAS](https://openlowcode.com/)
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0 .
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/

package org.openlowcode.server.data.properties;

import java.util.ArrayList;
import org.openlowcode.module.system.data.choice.ApplocaleChoiceDefinition;
import org.openlowcode.server.data.ChoiceValue;
import org.openlowcode.server.data.DataObject;
import org.openlowcode.server.data.DataObjectDefinition;
import org.openlowcode.server.data.DataObjectElement;
import org.openlowcode.server.data.DataObjectPayload;
import org.openlowcode.server.data.DataObjectPropertyDefinition;
import org.openlowcode.server.data.PropertyExtractor;
import org.openlowcode.server.data.loader.FlatFileLoaderColumn;
import org.openlowcode.server.data.properties.constraints.AutonamingRule;
import org.openlowcode.server.data.specificstorage.ExternalFieldSchema;
import org.openlowcode.server.data.storage.QueryCondition;
import org.openlowcode.server.data.storage.StoredTableIndex;
import org.openlowcode.server.data.storage.StringStoredField;

/**
 * Definition of the property providing a name to an object. A name is a short,
 * potentially non unique description of a business object. The name can be
 * generated by an auto-naming rule
 * 
 * @author <a href="https://openlowcode.com/" rel="nofollow">Open Lowcode
 *         SAS</a>
 *
 * @param <E> the data object
 */
public class NamedDefinition<E extends DataObject<E>> extends DataObjectPropertyDefinition<E> {
	private StringStoredField name;
	@SuppressWarnings("unused")
	private UniqueidentifiedDefinition<E> dependentdefinitionuniqueidentified;
	public final static int NAMED_LENGTH = 64;
	private String namelabel = "Name";
	private AutonamingRule<E> namingrule;

	/**
	 * creates the named definition
	 * 
	 * @param parentobject the definition of the parent object
	 */
	public NamedDefinition(DataObjectDefinition<E> parentobject) {
		super(parentobject, "NAMED");
		this.name = new StringStoredField("OBJECTNAME", null, NAMED_LENGTH);
		this.addFieldSchema(name);
		StoredTableIndex nameindex = new StoredTableIndex("NAME");
		nameindex.addStoredFieldSchema(name);
		this.addIndex(nameindex);
	}

	/**
	 * overrides the standard label 'Name'. For example, some data objects may want
	 * to put 'Label' or 'Description' as an alternative to 'Name' label
	 * 
	 * @param newlabel the new label
	 */
	public void overridesObjectnameLabel(String newlabel) {
		this.namelabel = newlabel;
	}

	/**
	 * gets the active name label
	 * 
	 * @return the label
	 */
	public String getNameLabel() {
		return this.namelabel;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public DataObjectElement initiateFieldInstance(DataObjectPayload parentpayload) {
		return new Named(this, parentpayload);
	}

	@Override
	public ArrayList<ExternalFieldSchema<?>> generateExternalSchema() {

		return null;
	}

	@Override
	public FieldSchemaForDisplay<E>[] setFieldSchemaToDisplay() {
		@SuppressWarnings("unchecked")
		FieldSchemaForDisplay<E>[] returnvalue = new FieldSchemaForDisplay[1];
		returnvalue[0] = new FieldSchemaForDisplay<E>(namelabel, "The name of the object. It is not enforced as unique",
				name, true, false, 800, NAMED_LENGTH, this.parentobject);
		return returnvalue;
	}

	/**
	 * sets a reference to the dependent property uniqueidentified definition
	 * 
	 * @param dependentdefinitionuniqueidentified the dependent property unique
	 *                                            identified definition
	 */
	public void setDependentDefinitionUniqueidentified(
			UniqueidentifiedDefinition<E> dependentdefinitionuniqueidentified) {
		this.dependentdefinitionuniqueidentified = dependentdefinitionuniqueidentified;
	}

	@Override
	public QueryCondition getUniversalQueryCondition(String alias) {

		return null;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public FlatFileLoaderColumn<E> getFlatFileLoaderColumn(DataObjectDefinition<E> objectdefinition,
			String[] columnattributes, PropertyExtractor<E> propertyextractor,
			ChoiceValue<ApplocaleChoiceDefinition> locale) {
		boolean truncate = true;
		if (columnattributes != null)
			for (int i = 0; i < columnattributes.length; i++) {
				if ("NOTRUNCATE".equals(columnattributes[i]))
					truncate = false;
			}
		return new NamedFlatFileLoader(objectdefinition, truncate);
	}

	@Override
	public String[] getLoaderFieldList() {
		return new String[] { "" };
	}

	@Override
	public String[] getLoaderFieldSample(String name) {
		String[] returntable = new String[4];
		returntable[0] = this.getName();
		returntable[1] = "OPTIONAL";
		returntable[2] = "The example object";
		returntable[3] = "Optional parameter: NOTRUNCATE will throw \nan error if name is too long. Else, it will just be truncated. ";
		return returntable;
	}

	/**
	 * Sets an auto-naming rule for this property
	 * 
	 * @param namingrule the auto-naming rule
	 */
	public void addAutonamingrule(AutonamingRule<E> namingrule) {
		this.namingrule = namingrule;

	}

	/**
	 * gets the auto-naming rule for this property
	 * 
	 * @return the auto-naming rule
	 */
	public AutonamingRule<E> getAutonamingRule() {
		return this.namingrule;
	}
}
